import { PageTmpItem } from './../domain/models/pageTmpItem';
import { IQueryObject } from 'tiny-entity2/queryObject';
import { TmpComItem } from './../domain/models/tmpComItem';
import { BaseService } from "./baseService";
import { Template } from "../domain/models/template";
import { ApiDataContext } from "../domain/apiDataContext";
import { Transaction } from "tiny-entity2";
import { Condition } from '../domain/models/condition';
import { Menu } from '../domain/models/menu';

export class TemplateService extends BaseService {
    CreateTemplate(entity: Template, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            // let has = await ctx.Template.First(x => x.name == $args1, { $args1: entity.name });
            // if (has) {
            //     throw new ServiceException(`已经存在名称【${entity.name}】的模板！`);
            // }
            let d = new Template();
            d.ConverToEntity(entity);
            return ctx.Create(d);
        });
    }
    UpdateTemplate(entity: Template, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            // let has = await ctx.Template.First(x => x.name == $args1 && x.id != $args2, { $args1: entity.name, $args2: entity.id });
            // if (has) {
            //     throw new ServiceException(`已经存在名称【${entity.name}】的模板！`);
            // }
            let d = new Template();
            d.ConverToEntity(entity);
            return ctx.Update(d);
        });
    }

    GetTemplateByOrgIdAndName(orgId: string, name: string) {
        let ctx = new ApiDataContext();
        return ctx.Template.First(x => x.orgId == $args1 && x.name == $args2, { $args1: orgId, $args2: name });
    }
    HasTemplate(id: string) {
        let ctx = new ApiDataContext();
        return ctx.Template.First(x => x.id == $args1, { $args1: id });
    }

    async GetTemplateById(id: string) {
        let ctx = new ApiDataContext();
        let r = await ctx.Template
            .Join(ctx.TmpComItem).On((m, f) => m.id == f.templateId)
            .Where(x => x.id == $args1, { $args1: id })
            .ToList();
        let result = r.length ? r[0] : null;

        if (result) {
            let condition = await ctx.Condition.Where(x => x.objectId == $args1, { $args1: id }).First();
            result.condition = condition;

            const list = result.tmpComItems.map(n => n.id);
            if (list.length > 0) {
                const tmpConditions = await ctx.Condition.Contains(x => x.objectId, list).ToList();
                for (let item of result.tmpComItems) {
                    item.condition = tmpConditions.find(x => x.objectId == item.id);
                }
            }
        }

        return result;
    }
    QueryTemplate(params: {
        orgId?: string;
    }) {
        let ctx = new ApiDataContext();
        let q = ctx.Template as IQueryObject<Template>;
        q = q.Join(ctx.TmpComItem).On((m, f) => m.id == f.templateId);
        if (params.orgId) {
            q = q.Where(x => x.orgId == $args1, { $args1: params.orgId });
        }

        return q.ToList();
    }

    async QueryTemplateWithMenuName(params: {
        orgId?: string;
    }) {
        let ctx = new ApiDataContext();
        let q = ctx.Template as IQueryObject<Template>;
        q = q.Join(ctx.TmpComItem).On((m, f) => m.id == f.templateId);
        if (params.orgId) {
            q = q.Where(x => x.orgId == $args1, { $args1: params.orgId });
        }

        let templates = await q.ToList();

        let menus = await ctx.Menu.Where(x => x.orgId == $args1, { $args1: params.orgId }).ToList();
        for (let item of menus) {
            let menuf: Menu;
            if (item.parentId) {
                menuf = menus.find(x => x.id == item.parentId);
            }
            if (item.workflowId) {
                let workflowNodeItems = await ctx.WorkflowNodeItem.Where(x => x.workflowId == $args1, { $args1: item.workflowId }).ToList();
                for (let wItem of workflowNodeItems) {
                    let pages = await ctx.Page.Where(x => x.flowNodeId == $args1, { $args1: wItem.flowNodeId }).ToList();
                    for (let page of pages) {
                        let pageTmpItems = await ctx.PageTmpItem.Where(x => x.pageId == $args1, { $args1: page.id }).ToList();
                        for (let pItem of pageTmpItems) {
                            let template = templates.find(x => x.id == pItem.templateId);
                            if (template) {
                                template.extends || (template.extends = {});
                                if (menuf) {
                                    template.extends.displayName = `${menuf.name}/${item.name}/${page.name}/${template.name}`;
                                }
                                else {
                                    template.extends.displayName = `${item.name}/${page.name}/${template.name}`;
                                }

                            }
                        }
                    }
                }
            }
            else {
                if (item.pageId) {
                    const page = await ctx.Page.First(x => x.id == $args1, { $args1: item.pageId });
                    if (!page) continue;
                    let pageTmpItems = await ctx.PageTmpItem.Where(x => x.pageId == $args1, { $args1: page.id }).ToList();
                    for (let pItem of pageTmpItems) {
                        let template = templates.find(x => x.id == pItem.templateId);
                        if (template) {
                            template.extends || (template.extends = {});
                            if (menuf) {
                                template.extends.displayName = `${menuf.name}/${item.name}/${template.name}`;
                            }
                            else {
                                template.extends.displayName = `${item.name}/${template.name}`;
                            }

                        }
                    }
                }
            }
        }

        templates = templates.filter(x => {
            if (x.extends && x.extends.displayName) {
                return true;
            }
            return false;
        });
        return templates;
    }

    GetTmpComItemById(id: string) {
        let ctx = new ApiDataContext();
        return ctx.TmpComItem.First(x => x.id == $args1, { $args1: id });
    }


    CreateTmpComItem(entity: TmpComItem, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new TmpComItem();
            d.ConverToEntity(entity);
            return ctx.Create(d);
        });
    }

    UpdateTmpComItem(entity: TmpComItem, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new TmpComItem();
            d.ConverToEntity(entity);
            return ctx.Update(d);
        });
    }

    DeleteTmpComItemByTemplate(tmpId: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let list = await ctx.TmpComItem.Where(x => x.templateId == $args1, { $args1: tmpId }).ToList();
            for (let item of list) {
                await ctx.Delete<Condition>(x => x.objectId == $args1, ctx.Condition, { $args1: item.id });
            }
            return ctx.Delete<TmpComItem>(x => x.templateId == $args1, ctx.TmpComItem, { $args1: tmpId });
        });
    }

    DeleteTmpComItem(entity: TmpComItem, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            return ctx.Delete(entity);
        });
    }

    DeleteTemplate(templateId: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            await ctx.Delete<PageTmpItem>(x => x.templateId == $args1, ctx.PageTmpItem, { $args1: templateId });
            await ctx.Delete<Template>(x => x.id == $args1, ctx.Template, { $args1: templateId });
            await ctx.Delete<TmpComItem>(x => x.templateId == $args1, ctx.TmpComItem, { $args1: templateId });
        });
    }

    DeleteTemplateByPageId(pageId: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let list = await ctx.PageTmpItem.Where(x => x.pageId == $args1, { $args1: pageId }).ToList();
            for (let item of list) {
                await ctx.Delete<Template>(x => x.id == $args1, ctx.Template, { $args1: item.templateId });
                await ctx.Delete<PageTmpItem>(x => x.templateId == $args1, ctx.PageTmpItem, { $args1: item.templateId });
                await ctx.Delete<TmpComItem>(x => x.templateId == $args1, ctx.TmpComItem, { $args1: item.templateId });
            }
        });
    }

    DeleteTemplateRefByPageId(pageId: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let list = await ctx.PageTmpItem.Where(x => x.pageId == $args1, { $args1: pageId }).ToList();
            for (let item of list) {
                // await ctx.Delete<Template>(x => x.id == $args1, ctx.Template, { $args1: item.templateId });
                await ctx.Delete<PageTmpItem>(x => x.templateId == $args1, ctx.PageTmpItem, { $args1: item.templateId });

                await ctx.Delete<Condition>(x => x.objectId == $args1, ctx.Condition, { $args1: item.templateId });

                const tmpComItems = await ctx.TmpComItem.Where(x => x.templateId == $args1, { $args1: item.templateId }).Select(x => x.id).ToList();
                for (let tmpItem of tmpComItems) {
                    await ctx.Delete<Condition>(x => x.objectId == $args1, ctx.Condition, { $args1: tmpItem.id });
                }

                await ctx.Delete<TmpComItem>(x => x.templateId == $args1, ctx.TmpComItem, { $args1: item.templateId });
            }
        });
    }

}